package handling.channel.handler;

import client.MapleBuffStat;
import client.MapleCharacter;
import client.MapleClient;
import client.PlayerStats;
import client.Skill;
import client.SkillFactory;
import client.anticheat.CheatTracker;
import client.anticheat.CheatingOffense;
import client.attactset;
import client.inventory.Equip;
import client.inventory.Item;
import client.inventory.MapleInventory;
import client.inventory.MapleInventoryType;
import client.status.MonsterStatus;
import client.status.MonsterStatusEffect;
import constants.GameConstants;
import handling.channel.ChannelServer;
import handling.login.LoginServer;
import handling.world.World.Broadcast;
import java.awt.Point;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.locks.Lock;
import org.apache.log4j.Logger;
import org.apache.mina.core.session.IoSession;
import server.MapleItemInformationProvider;
import server.MapleStatEffect;
import server.Randomizer;
import server.ServerProperties;
import server.life.Element;
import server.life.ElementalEffectiveness;
import server.life.MapleMonster;
import server.life.MapleMonsterStats;
import server.maps.Event_PyramidSubway;
import server.maps.MapleMap;
import server.maps.MapleMapItem;
import server.maps.MapleMapObject;
import server.maps.MapleMapObjectType;
import tools.AttackPair;
import tools.FileoutputUtil;
import tools.MaplePacketCreator;
import tools.Pair;
import tools.data.LittleEndianAccessor;

public class DamageParse {

    private static final Logger log = Logger.getLogger(DamageParse.class);

    public static void applyAttack(AttackInfo attack, Skill theSkill, MapleCharacter player, int attackCount, double maxDamagePerMonster, MapleStatEffect effect, AttackType attack_type) {
        if (ServerProperties.IsLvkejian()) {
            String SendTo = new StringBuilder().append("\r\n时间：").append(FileoutputUtil.CurrentReadable_Time()).append("  物理攻击检测 ---  0！").toString();
            player.dropMessage(-11, "物理攻击检测 ---  0！");

            FileoutputUtil.packetLog("log\\通过打怪伤害applyAttack详细信息.log", SendTo);
        }
        MapleMonster monster;
        if (!player.isAlive()) {
            player.getCheatTracker().registerOffense(CheatingOffense.ATTACKING_WHILE_DEAD, "操作者已死亡.");
            return;
        }
        if (player.isBanned()) {
            player.dropMessage(-11, "你已经被封停角色！无法使用攻击技能！");
            return;
        }
        if ((attack.real) && (GameConstants.getAttackDelay(attack.skill, theSkill) >= 100)) {
            player.getCheatTracker().checkAttack(attack.skill, attack.lastAttackTickCount);
        }
        if ((attack.skill != 0) && (attack.skill != 27121201)) {
            if ((effect == null) && (!GameConstants.夜光陨落星辰(attack.skill))) {
                player.getClient().getSession().write(MaplePacketCreator.enableActions());
                player.dropMessage(-11, "物理攻击检测 ---  1！");
                return;
            }
            if (GameConstants.isMulungSkill(attack.skill)) {
                if (player.getMapId() / 10000 != 92502) {
                    player.dropMessage(-11, "物理攻击检测 ---  2！");
                    return;
                }
                if (player.getMulungEnergy() < 10000) {
                    player.dropMessage(-11, "物理攻击检测 ---  3！");
                    return;
                }
                player.mulung_EnergyModify(false);
            } else if (GameConstants.isPyramidSkill(attack.skill)) {
                if (player.getMapId() / 1000000 != 926) {
                    player.dropMessage(-11, "物理攻击检测 ---  4！");
                    return;
                }
                if ((player.getPyramidSubway() == null) || (!player.getPyramidSubway().onSkillUse(player))) {
                    player.dropMessage(-11, "物理攻击检测 ---  5！");
                }
            } else if (GameConstants.isInflationSkill(attack.skill)) {
                if (player.getBuffedValue(MapleBuffStat.GIANT_POTION) == null) {
                    player.dropMessage(-11, "物理攻击检测 ---  6！");
                }
            } else if ((attack.targets > effect.getMobCount() * 2) && (attack.skill != 1211002) && (attack.skill != 1220010)) {
                player.getCheatTracker().registerOffense(CheatingOffense.MISMATCHING_BULLETCOUNT, "异常的攻击次数.");
                player.dropMessage(-11, "物理攻击检测 ---  7！");
                return;
            }
        }
        if ((player.getClient().getChannelServer().isAdminOnly()) && (player.isAdmin())) {
            player.dropMessage(-1, new StringBuilder().append("Animation: ").append(Integer.toHexString((attack.display & 0x8000) != 0 ? attack.display - 32768 : attack.display)).toString());
        }
        if (GameConstants.is夜光(player.getJob())) {
            player.setReborn(attack.skill);
            if (player.isLvkejian()) {
                player.dropMessage(new StringBuilder().append("夜光模式 = ").append(player.getYgMs()).append("  技能ID = ").append(player.getReborn()).toString());
            }
            if ((player.getYgMs() != 20040216) && (player.getYgMs() != 20040217) && (player.getYgMs() != 20040219)) {
                if (GameConstants.夜光光明技能(attack.skill)) {
                    SkillFactory.getSkill(20040216).getEffect(player.getTotalSkillLevel(20040216)).applyTo(player);
                    player.setYgMs(20040216);
                } else {
                    SkillFactory.getSkill(20040217).getEffect(player.getTotalSkillLevel(20040217)).applyTo(player);
                    player.setYgMs(20040217);
                }
            }
        } else if (GameConstants.is恶魔复仇者(player.getJob())) {
            if (GameConstants.is恶魔复仇者超越技能(attack.skill)) {
                int skils = GameConstants.is恶魔复仇者超越技能返回技能(attack.skill);
                player.set超越(player.get超越() + 1);
                if (player.isLvkejian()) {
                    player.dropMessage(new StringBuilder().append("恶魔复仇者超越技能 = ").append(attack.skill).append(" skils = ").append(skils).append(" 超越次数 ").append(player.get超越()).toString());
                }
                SkillFactory.getSkill(30010230).getEffect(1).applyTo(player);
                SkillFactory.getSkill(skils).getEffect(1).applyTo(player);
            }
        } else if (GameConstants.is恶魔猎手(player.getJob())) {
            if (player.getBuffedValue(MapleBuffStat.恶魔猎手蓝血) != null) {
                attackCount += attackCount;
            }
        } else if ((GameConstants.is萝莉(player.getJob()))
                && (Randomizer.nextInt(100) > 10) && ((attack.skill == 65121101) || (attack.skill == 65121107) || (attack.skill == 65121108))) {
            player.萝莉技能重生(attack.skill);
        }

        boolean useAttackCount = (!GameConstants.尖兵技能(attack.skill)) && (!GameConstants.魂骑士技能(attack.skill)) && (!GameConstants.is夜光技能(attack.skill)) && (!GameConstants.is风灵狂风肆虐(attack.skill)) && (attack.skill != 3121015) && (attack.skill != 3121014) && (attack.skill != 13121052) && (attack.skill != 3120010) && (attack.skill != 13001020) && (attack.skill != 13111021) && (attack.skill != 4211006) && (attack.skill != 3221007) && (attack.skill != 23121003) && ((attack.skill != 1311001) || (player.getJob() != 132)) && (attack.skill != 3211006) && (attack.skill != 24100003) && (attack.skill != 3121052) && (attack.skill != 33121052) && (attack.skill != 1120017) && (attack.skill != 3221017) && (attack.skill != 3221017) && (attack.skill != 3221017) && (attack.skill != 24120002);

        if ((attack.hits > attackCount * 2) && (useAttackCount)) {
            if ((player.isGM()) && (ServerProperties.ShowPacket())) {
                player.dropMessage(-5, new StringBuilder().append("物理攻击次数检测 attack.hits ").append(attack.hits).append(" attackCount ").append(attackCount).toString());
            }

            player.getCheatTracker().registerOffense(CheatingOffense.MISMATCHING_BULLETCOUNT, "异常的攻击次数.");
            log.info(new StringBuilder().append("[作弊] ").append(player.getName()).append(" 物理攻击次数异常。 attack.hits ").append(attack.hits).append(" attackCount ").append(attackCount).append(" 技能ID ").append(attack.skill).toString());
            Broadcast.broadcastGMMessage(MaplePacketCreator.serverNotice(6, new StringBuilder().append("[GM Message] ").append(player.getName()).append(" (等级 ").append(player.getLevel()).append(") 物理攻击次数异常。 attack.hits ").append(attack.hits).append(" attackCount ").append(attackCount).append(" 技能ID ").append(attack.skill).toString()));
            return;
        }

        if ((attack.hits > 0) && (attack.targets > 0)) {
            if (!player.getStat().checkEquipDurabilitys(player, -1)) {
                player.dropMessage(5, "An item has run out of durability but has no inventory room to go to.");
                return;
            }
        }

        int totDamage = 0;
        MapleMap map = player.getMap();
        Point Original_Pos = player.getPosition();

        //金钱炸弹
        if (attack.skill == 4211006) {
            for (AttackPair oned : attack.allDamage) {
                if (oned.attack == null) {
                    MapleMapObject mapobject = map.getMapObject(oned.objectid, MapleMapObjectType.ITEM);
                    player.dropMessage(-11, "物理攻击检测 ---  8！");

                    if (mapobject != null) {
                        MapleMapItem mapitem = (MapleMapItem) mapobject;
                        mapitem.getLock().lock();
                        try {
                            if (mapitem.getMeso() > 0) {
                                if (mapitem.isPickedUp()) {
                                    player.dropMessage(-11, "物理攻击检测 ---  9！");
                                    return;
                                }
                                map.removeMapObject(mapitem);
                                map.broadcastMessage(MaplePacketCreator.explodeDrop(mapitem.getObjectId()));
                                mapitem.setPickedUp(true);
                            } else {
                                player.getCheatTracker().registerOffense(CheatingOffense.ETC_EXPLOSION, "异常的技能效果.");
                                player.dropMessage(-11, "物理攻击检测 ---  10！");
                                return;
                            }
                        } finally {
                            mapitem.getLock().unlock();
                        }
                    } else {
                        player.getCheatTracker().registerOffense(CheatingOffense.EXPLODING_NONEXISTANT, "异常的技能效果.");
                        player.dropMessage(-11, "物理攻击检测 ---  11！");
                        return;
                    }
                }
            }
        }
        int totDamageToOneMonster = 0;
        long hpMob = 0L;
        PlayerStats stats = player.getStat();

        int CriticalDamage = stats.passive_sharpeye_percent();
        int ShdowPartnerAttackPercentage = 0;
        if ((attack_type == AttackType.RANGED_WITH_SHADOWPARTNER) || (attack_type == AttackType.NON_RANGED_WITH_MIRROR)) {
            MapleStatEffect shadowPartnerEffect = player.getStatForBuff(MapleBuffStat.影分身);
            if (shadowPartnerEffect != null) {
                ShdowPartnerAttackPercentage += shadowPartnerEffect.getX();
            }
            attackCount /= 2;
        }
        ShdowPartnerAttackPercentage *= (CriticalDamage + 100) / 100;
        if (attack.skill == 4221001) {
            ShdowPartnerAttackPercentage *= 10;
        }

        //蓝光连击
        if ((attack.skill == 24121000) && (attack.movei != null)) {
            if (player.isHidden()) {
                player.setLastRes(attack.movei);
                map.broadcastGMMessage(player, MaplePacketCreator.玩家_移动(player.getId(), attack.movei, Original_Pos), false);
            } else {
                map.broadcastMessage(player, MaplePacketCreator.玩家_移动(player.getId(), attack.movei, Original_Pos), false);
            }
            MovementParse.updatePosition(attack.movei, player, 0);
            Point pos = player.getTruePosition();
            map.movePlayer(player, pos);
        }

        double maxDamagePerHit = 0.0D;
        for (AttackPair oned : attack.allDamage) {
            monster = map.getMonsterByOid(oned.objectid);
            if ((monster != null) && (monster.getLinkCID() <= 0)) {
                totDamageToOneMonster = 0;
                hpMob = monster.getMobMaxHp();
                MapleMonsterStats monsterstats = monster.getStats();
                int fixeddmg = monsterstats.getFixedDamage();
                boolean Tempest = (monster.getStatusSourceID(MonsterStatus.结冰) == 21120006) || (attack.skill == 21120006) || (attack.skill == 1221011);
                if ((!Tempest) && (!player.isGM())) {
                    if (((player.getJob() >= 3200) && (player.getJob() <= 3212) && (!monster.isBuffed(MonsterStatus.免疫伤害)) && (!monster.isBuffed(MonsterStatus.免疫魔攻)) && (!monster.isBuffed(MonsterStatus.反射魔攻))) || (attack.skill == 3221007) || (attack.skill == 23121003) || (((player.getJob() < 3200) || (player.getJob() > 3212)) && (!monster.isBuffed(MonsterStatus.免疫伤害)) && (!monster.isBuffed(MonsterStatus.免疫物攻)) && (!monster.isBuffed(MonsterStatus.反射物攻)))) {
                        maxDamagePerHit = CalculateMaxWeaponDamagePerHit(player, monster, attack, theSkill, effect, maxDamagePerMonster, Integer.valueOf(CriticalDamage)) * 100.0D;
                    } else {
                        maxDamagePerHit = 1.0D;
                    }
                }
                byte overallAttackCount = 0;

                int criticals = 0;
                for (Pair eachde : oned.attack) {
                    Integer eachd = (Integer) eachde.left;
                    overallAttackCount = (byte) (overallAttackCount + 1);
                    if (((Boolean) eachde.right)) {
                        criticals++;
                    }
                    if ((useAttackCount) && (overallAttackCount - 1 == attackCount)) {
                        maxDamagePerHit = maxDamagePerHit / 100.0D * (ShdowPartnerAttackPercentage * (monsterstats.isBoss() ? stats.bossdam_r : stats.dam_r) / 100.0D);
                    }

                    if (fixeddmg != -1) {
                        if (monsterstats.getOnlyNoramlAttack()) {
                            eachd = attack.skill != 0 ? 0 : fixeddmg;
                        } else {
                            eachd = fixeddmg;
                        }
                    } else if (monsterstats.getOnlyNoramlAttack()) {
                        eachd = attack.skill != 0 ? 0 : Math.min(eachd, (int) maxDamagePerHit);
                    } else if (!player.isGM()) {
                        if (Tempest) {
                            if (eachd > monster.getMobMaxHp()) {
                                eachd = (int) Math.min(monster.getMobMaxHp(), 2147483647L);
                                player.getCheatTracker().registerOffense(CheatingOffense.HIGH_DAMAGE, "攻击伤害过高.");
                            }
                        } else if (((player.getJob() >= 3200) && (player.getJob() <= 3212) && (!monster.isBuffed(MonsterStatus.免疫伤害)) && (!monster.isBuffed(MonsterStatus.免疫魔攻)) && (!monster.isBuffed(MonsterStatus.反射魔攻))) || (attack.skill == 23121003) || (((player.getJob() < 3200) || (player.getJob() > 3212)) && (!monster.isBuffed(MonsterStatus.免疫伤害)) && (!monster.isBuffed(MonsterStatus.免疫物攻)) && (!monster.isBuffed(MonsterStatus.反射物攻)))) {
                            if ((eachd > maxDamagePerHit) && (maxDamagePerHit > 1000.0D)) {
                                player.getCheatTracker().registerOffense(CheatingOffense.HIGH_DAMAGE, new StringBuilder().append("[伤害: ").append(eachd).append(", 预计伤害: ").append(maxDamagePerHit).append(", 怪物ID: ").append(monster.getId()).append("] [职业: ").append(player.getJob()).append(", 等级: ").append(player.getLevel()).append(", 技能: ").append(attack.skill).append("]").toString());
                                if (attack.real) {
                                    player.getCheatTracker().checkSameDamage(eachd, maxDamagePerHit);
                                }
                                if (eachd > maxDamagePerHit * 3.0D) {
                                    player.getCheatTracker().registerOffense(CheatingOffense.HIGH_DAMAGE_2, new StringBuilder().append("[Damage: ").append(eachd).append(", Expected: ").append(maxDamagePerHit).append(", Mob: ").append(monster.getId()).append("] [Job: ").append(player.getJob()).append(", Level: ").append(player.getLevel()).append(", Skill: ").append(attack.skill).append("]").toString());
                                    eachd = (int) (maxDamagePerHit * 2.0D);
                                    if (eachd.intValue() >= 2499999) {
                                        System.err.println("there 287");
                                        player.getClient().getSession().close(true);
                                        if (ServerProperties.IsLvkejian()) {
                                            String SendTo = new StringBuilder().append("\r\n时间：").append(FileoutputUtil.CurrentReadable_Time()).append("  对玩家进行掉线处理 ----30 ").toString();
                                            FileoutputUtil.packetLog("log\\玩家进行掉线处理.log", SendTo);
                                        }
                                        player.dropMessage(-11, "物理攻击检测 ---  12！");
                                    }
                                }
                            }
                        } else if (eachd > maxDamagePerHit) {
                            eachd = (int) maxDamagePerHit;
                        }

                    }

                    if (player == null) {
                        player.dropMessage(-11, "物理攻击检测 ---  13 玩家不存在！");
                        return;
                    }
                    totDamageToOneMonster += eachd;

                    if (((eachd == 0) || (monster.getId() == 9700021)) && (player.getPyramidSubway() != null)) {
                        player.getPyramidSubway().onMiss(player);
                    }
                }
                totDamage += totDamageToOneMonster;
                player.checkMonsterAggro(monster);

                if ((GameConstants.getAttackDelay(attack.skill, theSkill) >= 100) && (!GameConstants.isNoDelaySkill(attack.skill)) && (!GameConstants.is不检测范围(attack.skill)) && (!monster.getStats().isBoss()) && (player.getTruePosition().distanceSq(monster.getTruePosition()) > GameConstants.getAttackRange(effect, player.getStat().defRange) * 1.2D)) {
                    Broadcast.broadcastGMMessage(MaplePacketCreator.serverNotice(6, new StringBuilder().append("[GM Message] ").append(player.getName()).append(" (等级 ").append(player.getLevel()).append(") 攻击范围异常。 地图ID: ").append(player.getMapId()).append(" 职业: ").append(player.getJob()).toString()));
                    player.getCheatTracker().registerOffense(CheatingOffense.ATTACK_FARAWAY_MONSTER, new StringBuilder().append("[范围: ").append(player.getTruePosition().distanceSq(monster.getTruePosition())).append(", 预期范围: ").append(GameConstants.getAttackRange(effect, player.getStat().defRange)).append(" 职业: ").append(player.getJob()).append("]").toString());
                }

                if (player.getSkillLevel(36110005) > 0) {
                    Skill skill = SkillFactory.getSkill(36110005);
                    MapleStatEffect eff = skill.getEffect(player.getSkillLevel(skill));
                    if (player.getLastCombo() + 5000 < System.currentTimeMillis()) {
                        monster.setTriangulation(0);
                        //player.clearDamageMeters();
                    }
                    if (eff.makeChanceResult()) {
                        player.setLastCombo(System.currentTimeMillis());
                        if (monster.getTriangulation() < 3) {
                            monster.setTriangulation(monster.getTriangulation() + 1);
                        }
                        //monster.applyStatus(player, new MonsterStatusEffect(MonsterStatus.心灵控制, eff.getX(), eff.getSourceId(), null, false), false, eff.getY() * 1000, true, eff);
                        //monster.applyStatus(player, new MonsterStatusEffect(MonsterStatus.三角进攻, monster.getTriangulation(), eff.getSourceId(), null, false), false, eff.getY() * 1000, true, eff);
                    }
                }

                if (player.getBuffedValue(MapleBuffStat.敛财术) != null) {
                    switch (attack.skill) {
                        case 0:
                        case 4001334:
                        case 4201005:
                        case 4211002:
                        case 4211011:
                        case 4221007:
                        case 4221010:
                            handlePickPocket(player, monster, oned);
                    }
                }

                if ((player.getattack(1) != null) && (player.getMapId() >= player.getattack(1).minmapid) && (player.getMapId() <= player.getattack(1).maxmapid)) {
                    totDamageToOneMonster /= player.getattack(1).attack;
                }

                if (ServerProperties.IsLvkejian()) {
                    String SendTo = new StringBuilder().append("\r\n时间：").append(FileoutputUtil.CurrentReadable_Time()).append("  物理攻击检测 ---  15！").toString();

                    FileoutputUtil.packetLog("log\\通过打怪伤害applyAttack详细信息.log", SendTo);
                }

                if ((totDamageToOneMonster > 0) || (GameConstants.尖兵技能(attack.skill)) || (attack.skill == 1221011) || (attack.skill == 21120006) || (attack.skill == 27121201) || (attack.skill == 61001101)) {
                    if ((monster.getStats().isBoss()) && (!player.isLvkejian()) && (ServerProperties.IsBossDamage())) {
                        totDamage /= 2;
                    }

                    if (attack.skill != 1221011) {
                        monster.damage(player, totDamageToOneMonster, true, attack.skill);
                    } else {
                        monster.damage(player, monster.getStats().isBoss() ? 500000L : monster.getHp() - 1L, true, attack.skill);
                    }
                    if (monster.isBuffed(MonsterStatus.反射物攻)) {
                        player.addHP(-(7000 + Randomizer.nextInt(8000)));
                    }
                    player.onAttack(monster.getMobMaxHp(), monster.getMobMaxMp(), attack.skill, monster.getObjectId(), totDamage);

                    if (GameConstants.is恶魔猎手(player.getJob())) {
                        player.handleForceGain(monster.getObjectId(), attack.skill);
                    } else if (GameConstants.is神之子(player.getJob())) {
                        int 概率 = Randomizer.nextInt(10);
                        int sl = 1;
                        if (概率 > 5) {
                            sl = 2;
                        } else if (概率 > 7) {
                            sl = 3;
                        } else if (概率 > 8) {
                            sl = 4;
                        } else if (概率 > 9) {
                            sl = 5;
                        }
                        int moblv = monster.getStats().getLevel();
                        if ((player.getLevel() < moblv + 20) || (moblv > 180)) {
                            Point pos = monster.getPosition();
                            player.神之子WP球显示(pos, monster.getObjectId(), attack.skill, sl);
                        }
                        if (概率 > 1) {
                            int skill = 100000276;
                            if (GameConstants.is神之子_贝塔技能(attack.skill)) {
                                skill = 100000277;
                            }
                            SkillFactory.getSkill(skill).getEffect(1).applyTo(player);
                        }
                    }
                    if (ServerProperties.IsLvkejian()) {
                        String SendTo = new StringBuilder().append("\r\n时间：").append(FileoutputUtil.CurrentReadable_Time()).append("  开始截取 伤害数据 -- 物理攻击 \r\n").toString();

                        FileoutputUtil.packetLog("log\\通过打怪伤害applyAttack详细信息.log", SendTo);
                    }

                    switch (attack.skill) {
                        case 4001334:
                        case 4001344:
                        case 4101008:
                        case 4101010:
                        case 4111010:
                        case 4111013:
                        case 4121013:
                        case 4201005:
                        case 4211002:
                        case 4211011:
                        case 4221001:
                        case 4221007:
                        case 4221010:
                        case 4301001:
                        case 4311002:
                        case 4311003:
                        case 4321004:
                        case 4331000:
                        case 4331005:
                        case 4331006:
                        case 4341002:
                        case 4341004:
                        case 4341009:
                        case 14001004:
                        case 14101008:
                        case 14101009:
                        case 14111005:
                        case 14111008:
                            int[] skills = {4110011, 4210010, 4320005, 14110004};
                            for (int i : skills) {
                                Skill skill = SkillFactory.getSkill(i);
                                if (player.getTotalSkillLevel(skill) > 0) {
                                    MapleStatEffect venomEffect = skill.getEffect(player.getTotalSkillLevel(skill));
                                    if (!venomEffect.makeChanceResult()) {
                                        break;
                                    }
                                    monster.applyStatus(player, new MonsterStatusEffect(MonsterStatus.中毒, Integer.valueOf(1), i, player.getSkillLevel(i), null, false), true, venomEffect.getDuration(), true, venomEffect);
                                    break;
                                }

                            }

                            break;
                        case 4201004:
                            monster.handleSteal(player);
                            break;
                        case 21000002:
                        case 21000004:
                        case 21100001:
                        case 21100002:
                        case 21100007:
                        case 21110002:
                        case 21110003:
                        case 21110004:
                        case 21110006:
                        case 21110007:
                        case 21110008:
                        case 21120002:
                        case 21120005:
                        case 21120006:
                        case 21120007:
                        case 21120009:
                        case 21120010:
                            if ((player.getBuffedValue(MapleBuffStat.属性攻击) != null) && (!monster.getStats().isBoss())) {
                                MapleStatEffect eff = player.getStatForBuff(MapleBuffStat.属性攻击);
                                if (eff != null) {
                                    monster.applyStatus(player, new MonsterStatusEffect(MonsterStatus.速度, Integer.valueOf(eff.getX()), eff.getSourceId(), player.getSkillLevel(eff.getSourceId()), null, false), false, eff.getY() * 1000, true, eff);
                                }
                            }
                            if ((player.getBuffedValue(MapleBuffStat.战神抗压) != null) && (!monster.getStats().isBoss())) {
                                MapleStatEffect eff = player.getStatForBuff(MapleBuffStat.战神抗压);
                                if ((eff != null) && (eff.makeChanceResult()) && (!monster.isBuffed(MonsterStatus.抗压))) {
                                    monster.applyStatus(player, new MonsterStatusEffect(MonsterStatus.抗压, Integer.valueOf(1), eff.getSourceId(), player.getSkillLevel(eff.getSourceId()), null, false), false, eff.getX() * 1000, true, eff);
                                }
                            }
                            break;
                    }
                    if (totDamageToOneMonster > 0) {
                        Item weapon_ = player.getInventory(MapleInventoryType.EQUIPPED).getItem((short) -11);
                        if (weapon_ != null) {
                            MonsterStatus stat = GameConstants.getStatFromWeapon(weapon_.getItemId());
                            if ((stat != null) && (Randomizer.nextInt(100) < GameConstants.getStatChance())) {
                                MonsterStatusEffect monsterStatusEffect = new MonsterStatusEffect(stat, Integer.valueOf(GameConstants.getXForStat(stat)), GameConstants.getSkillForStat(stat), player.getSkillLevel(GameConstants.getSkillForStat(stat)), null, false);
                                monster.applyStatus(player, monsterStatusEffect, false, 10000L, false, null);
                            }
                        }
                        if (player.getBuffedValue(MapleBuffStat.致盲) != null) {
                            MapleStatEffect eff = player.getStatForBuff(MapleBuffStat.致盲);
                            if ((eff != null) && (eff.makeChanceResult())) {
                                MonsterStatusEffect monsterStatusEffect = new MonsterStatusEffect(MonsterStatus.命中, Integer.valueOf(eff.getX()), eff.getSourceId(), player.getSkillLevel(eff.getSourceId()), null, false);
                                monster.applyStatus(player, monsterStatusEffect, false, eff.getY() * 1000, true, eff);
                            }
                        }
                        if (player.getBuffedValue(MapleBuffStat.幻影步) != null) {
                            MapleStatEffect eff = player.getStatForBuff(MapleBuffStat.幻影步);
                            if ((eff != null) && (eff.makeChanceResult())) {
                                MonsterStatusEffect monsterStatusEffect = new MonsterStatusEffect(MonsterStatus.速度, Integer.valueOf(eff.getX()), 3121007, player.getSkillLevel(3121007), null, false);
                                monster.applyStatus(player, monsterStatusEffect, false, eff.getY() * 1000, true, eff);
                            }
                        }
                        if ((player.getJob() == 121) || (player.getJob() == 122)) {
                            Skill skill = SkillFactory.getSkill(1211006);
                            if (player.isBuffFrom(MapleBuffStat.属性攻击, skill)) {
                                MapleStatEffect eff = skill.getEffect(player.getTotalSkillLevel(skill));
                                MonsterStatusEffect monsterStatusEffect = new MonsterStatusEffect(MonsterStatus.结冰, Integer.valueOf(1), skill.getId(), player.getSkillLevel(skill.getId()), null, false);
                                monster.applyStatus(player, monsterStatusEffect, false, eff.getY() * 2000, true, eff);
                            }
                        }
                    }
                    if ((effect != null) && (effect.getMonsterStati().size() > 0) && (effect.makeChanceResult())) {
                        for (Map.Entry z : effect.getMonsterStati().entrySet()) {
                            monster.applyStatus(player, new MonsterStatusEffect((MonsterStatus) z.getKey(), (Integer) z.getValue(), theSkill.getId(), player.getSkillLevel(theSkill.getId()), null, false), effect.isPoison(), effect.getDuration(), true, effect);
                        }
                    }
                }
            }
        }
        //MapleMonster monster;
        if ((attack.skill == 4331003) && ((hpMob <= 0L) || (totDamageToOneMonster < hpMob))) {
            return;
        }
        if ((hpMob > 0L) && (totDamageToOneMonster > 0)) {
            player.afterAttack(attack.targets, attack.hits, attack.skill);
        }
        if ((attack.skill != 0) && ((attack.targets > 0) || (attack.skill != 4341002) || (attack.skill != 27121201)) && (!GameConstants.isNoDelaySkill(attack.skill))) {
            //effect.applyTo(player, attack.position);
            boolean applyTo = effect.applyTo(player, attack.position);
        }
        if ((totDamage > 1) && (GameConstants.getAttackDelay(attack.skill, theSkill) >= 100)) {
            CheatTracker tracker = player.getCheatTracker();
            tracker.setAttacksWithoutHit(true);
            if (tracker.getAttacksWithoutHit() >= 100) {
                tracker.registerOffense(CheatingOffense.ATTACK_WITHOUT_GETTING_HIT, "无敌自动封号.");
            }
        }
    }

    public static void applyAttackMagic(AttackInfo attack, Skill theSkill, MapleCharacter player, MapleStatEffect effect, double maxDamagePerHit) {
        if (!player.isAlive()) {
            player.getCheatTracker().registerOffense(CheatingOffense.ATTACKING_WHILE_DEAD);
            player.dropMessage(-11, "魔法攻击检测 ---- 1 玩家已经死亡！");
            return;
        }
        if ((attack.real) && (GameConstants.getAttackDelay(attack.skill, theSkill) >= 100)) {
            player.getCheatTracker().checkAttack(attack.skill, attack.lastAttackTickCount);
            System.out.println("Return 8");
            System.out.println("Return 8 with skill " + attack.skill);
        }

        if (effect.getBulletCount() > 1) {
            if ((attack.hits > effect.getBulletCount()) || (attack.targets > effect.getMobCount())) {
                player.getCheatTracker().registerOffense(CheatingOffense.MISMATCHING_BULLETCOUNT);
                System.out.println("Return 9");
                return;
            }

        }

        if (GameConstants.is夜光(player.getJob())) {
            if (player.isLvkejian()) {
                player.dropMessage(new StringBuilder().append("夜光模式 = ").append(player.getYgMs()).toString());
            }
            if ((player.getYgMs() != 20040216) && (player.getYgMs() != 20040217) && (player.getYgMs() != 20040219)) {
                if (GameConstants.夜光光明技能(attack.skill)) {
                    SkillFactory.getSkill(20040216).getEffect(player.getTotalSkillLevel(20040216)).applyTo(player);
                    player.setYgMs(20040216);
                } else {
                    SkillFactory.getSkill(20040217).getEffect(player.getTotalSkillLevel(20040217)).applyTo(player);
                    player.setYgMs(20040217);
                }
            }
        }

        if (((attack.hits > effect.getAttackCount() * 2) || (attack.targets > effect.getMobCount() * 2)) && (!GameConstants.is夜光技能(attack.skill))) {
            if ((player.isGM()) && (ServerProperties.ShowPacket())) {
                player.dropMessage(-5, new StringBuilder().append("魔法攻击次数检测  attack.hits ").append(attack.hits).append(" attackCount ").append(effect.getAttackCount()).append(" attack.targets ").append(attack.targets).append(" MobCount ").append(effect.getMobCount()).toString());
            }

            player.getCheatTracker().registerOffense(CheatingOffense.MISMATCHING_BULLETCOUNT, "异常的攻击次数.");
            log.info(new StringBuilder().append("[作弊] ").append(player.getName()).append(" 魔法攻击次数异常。attack.hits ").append(attack.hits).append(" attackCount ").append(effect.getAttackCount()).append(" attack.targets ").append(attack.targets).append(" MobCount ").append(effect.getMobCount()).toString());
            Broadcast.broadcastGMMessage(MaplePacketCreator.serverNotice(6, new StringBuilder().append("[GM Message] ").append(player.getName()).append(" (等级 ").append(player.getLevel()).append(") 魔法攻击次数异常。attack.hits ").append(attack.hits).append(" attackCount ").append(effect.getAttackCount()).append(" attack.targets ").append(attack.targets).append(" MobCount ").append(effect.getMobCount()).append(" 技能ID ").append(attack.skill).toString()));
            return;
        }

        if ((attack.hits > 0) && (attack.targets > 0) && (!player.getStat().checkEquipDurabilitys(player, -1))) {
            player.dropMessage(5, "An item has run out of durability but has no inventory room to go to.");
            System.out.println("Return 11");
            return;
        }

        if (GameConstants.isMulungSkill(attack.skill)) {
            if (player.getMapId() / 10000 != 92502) {
                return;
            }
            if (player.getMulungEnergy() < 10000) {
                player.dropMessage(-11, "魔法攻击检测 ---- 2！");
                return;
            }
            player.mulung_EnergyModify(false);
        } else if (GameConstants.isPyramidSkill(attack.skill)) {
            if (player.getMapId() / 1000000 != 926) {
                return;
            }
            if ((player.getPyramidSubway() == null) || (!player.getPyramidSubway().onSkillUse(player))) {
                player.dropMessage(-11, "魔法攻击检测 ---- 3！");
            }
        } else if ((GameConstants.isInflationSkill(attack.skill)) && (player.getBuffedValue(MapleBuffStat.GIANT_POTION) == null)) {
            player.dropMessage(-11, "魔法攻击检测 ---- 4！");
            return;
        }

        if ((player.getClient().getChannelServer().isAdminOnly()) && (player.isAdmin())) {
            player.dropMessage(-1, new StringBuilder().append("Animation: ").append(Integer.toHexString((attack.display & 0x8000) != 0 ? attack.display - 32768 : attack.display)).toString());
        }
        PlayerStats stats = player.getStat();
        Element element = player.getBuffedValue(MapleBuffStat.自然力重置) != null ? Element.NEUTRAL : theSkill.getElement();

        double MaxDamagePerHit = 0.0D;
        int totDamage = 0;

        int CriticalDamage = stats.passive_sharpeye_percent();
        Skill eaterSkill = SkillFactory.getSkill(GameConstants.getMPEaterForJob(player.getJob()));
        int eaterLevel = player.getTotalSkillLevel(eaterSkill);

        MapleMap map = player.getMap();
        for (AttackPair oned : attack.allDamage) {
            MapleMonster monster = map.getMonsterByOid(oned.objectid);
            if ((monster != null) && (monster.getLinkCID() <= 0)) {
                boolean Tempest = (monster.getStatusSourceID(MonsterStatus.结冰) == 21120006) && (!monster.getStats().isBoss());
                int totDamageToOneMonster = 0;
                MapleMonsterStats monsterstats = monster.getStats();
                int fixeddmg = monsterstats.getFixedDamage();
                if ((!Tempest) && (!player.isGM())) {
                    if ((!monster.isBuffed(MonsterStatus.免疫魔攻)) && (!monster.isBuffed(MonsterStatus.反射魔攻))) {
                        MaxDamagePerHit = CalculateMaxMagicDamagePerHit(player, theSkill, monster, monsterstats, stats, element, Integer.valueOf(CriticalDamage), maxDamagePerHit, effect) * 10000.0D;
                    } else {
                        MaxDamagePerHit = 1.0D;
                    }
                }
                byte overallAttackCount = 0;

                for (Pair eachde : oned.attack) {
                    Integer eachd = (Integer) eachde.left;
                    overallAttackCount = (byte) (overallAttackCount + 1);
                    if (fixeddmg != -1) {
                        eachd = monsterstats.getOnlyNoramlAttack() ? 0 : fixeddmg;
                    } else if (monsterstats.getOnlyNoramlAttack()) {
                        eachd = 0;
                    } else if (!player.isGM()) {
                        if (Tempest) {
                            if (eachd > monster.getMobMaxHp()) {
                                eachd = (int) Math.min(monster.getMobMaxHp(), 2147483647L);

                                player.getCheatTracker().registerOffense(CheatingOffense.HIGH_DAMAGE_MAGIC, "攻击伤害过高.");
                            }
                        } else if ((!monster.isBuffed(MonsterStatus.免疫魔攻)) && (!monster.isBuffed(MonsterStatus.反射魔攻))) {
                            if ((eachd > MaxDamagePerHit) && (MaxDamagePerHit > 100000.0D)) {
                                player.getCheatTracker().registerOffense(CheatingOffense.HIGH_DAMAGE_MAGIC, new StringBuilder().append("[伤害: ").append(eachd).append(", 预期: ").append(MaxDamagePerHit).append(", 怪物ID: ").append(monster.getId()).append("] [职业: ").append(player.getJob()).append(", 等级: ").append(player.getLevel()).append(", 技能: ").append(attack.skill).append("]").toString());
                                if (attack.real) {
                                    player.getCheatTracker().checkSameDamage(eachd, MaxDamagePerHit);
                                }
                                if (eachd > MaxDamagePerHit * 2.0D) {
                                    player.getCheatTracker().registerOffense(CheatingOffense.HIGH_DAMAGE_MAGIC_2, new StringBuilder().append("[伤害: ").append(eachd).append(", 预期: ").append(MaxDamagePerHit).append(", 怪物ID: ").append(monster.getId()).append("] [职业: ").append(player.getJob()).append(", 等级: ").append(player.getLevel()).append(", 技能: ").append(attack.skill).append("]").toString());
                                    eachd = (int) (MaxDamagePerHit * 2.0D);
                                    if (eachd >= 2499999) {
                                        System.err.println("there 675");
                                        player.getClient().getSession().close(true);
                                        if (ServerProperties.IsLvkejian()) {
                                            String SendTo = new StringBuilder().append("\r\n时间：").append(FileoutputUtil.CurrentReadable_Time()).append("  对玩家进行掉线处理 ----31 ").toString();
                                            FileoutputUtil.packetLog("log\\玩家进行掉线处理.log", SendTo);
                                        }
                                    }
                                }
                            }
                        } else if (eachd > MaxDamagePerHit) {
                            eachd = (int) MaxDamagePerHit;
                        }

                    }

                    totDamageToOneMonster += eachd;
                }

                totDamage += totDamageToOneMonster;
                player.checkMonsterAggro(monster);

                if ((GameConstants.getAttackDelay(attack.skill, theSkill) >= 100) && (!GameConstants.isNoDelaySkill(attack.skill)) && (!GameConstants.is不检测范围(attack.skill)) && (!monster.getStats().isBoss()) && (player.getTruePosition().distanceSq(monster.getTruePosition()) > GameConstants.getAttackRange(effect, player.getStat().defRange))) {
                    Broadcast.broadcastGMMessage(MaplePacketCreator.serverNotice(6, new StringBuilder().append("[GM Message] ").append(player.getName()).append(" (等级 ").append(player.getLevel()).append(") 攻击范围异常。 地图ID: ").append(player.getMapId()).append(" 职业: ").append(player.getJob()).toString()));
                    player.getCheatTracker().registerOffense(CheatingOffense.ATTACK_FARAWAY_MONSTER, new StringBuilder().append("[范围: ").append(player.getTruePosition().distanceSq(monster.getTruePosition())).append(", 预期范围: ").append(GameConstants.getAttackRange(effect, player.getStat().defRange)).append(" 职业: ").append(player.getJob()).append("]").toString());
                }
                if ((attack.skill == 2301002) && (!monsterstats.getUndead())) {
                    player.getCheatTracker().registerOffense(CheatingOffense.HEAL_ATTACKING_UNDEAD);
                    player.dropMessage(-11, "魔法攻击检测 ---- 5！");
                    return;
                }
                if (totDamageToOneMonster > 0) {
                    if ((monster.getStats().isBoss()) && (!player.isLvkejian()) && (ServerProperties.IsBossDamage())) {
                        totDamage /= 2;
                    }
                    monster.damage(player, totDamageToOneMonster, true, attack.skill);
                    if (monster.isBuffed(MonsterStatus.反射魔攻)) {
                        player.addHP(-(7000 + Randomizer.nextInt(8000)));
                    }
                    if (player.getBuffedValue(MapleBuffStat.缓速术) != null) {
                        MapleStatEffect eff = player.getStatForBuff(MapleBuffStat.缓速术);
                        if ((eff != null) && (eff.makeChanceResult()) && (!monster.isBuffed(MonsterStatus.速度))) {
                            monster.applyStatus(player, new MonsterStatusEffect(MonsterStatus.速度, Integer.valueOf(eff.getX()), eff.getSourceId(), player.getSkillLevel(eff.getSourceId()), null, false), false, eff.getY() * 1000, true, eff);
                        }
                    }

                    player.onAttack(monster.getMobMaxHp(), monster.getMobMaxMp(), attack.skill, monster.getObjectId(), totDamage);

                    if (ServerProperties.IsLvkejian()) {
                        String SendTo = new StringBuilder().append("\r\n时间：").append(FileoutputUtil.CurrentReadable_Time()).append("  开始截取 伤害数据 --- 魔法攻击 \r\n").toString();

                        FileoutputUtil.packetLog("log\\通过打怪伤害applyAttackMagic详细信息.log", SendTo);
                    }

                    switch (attack.skill) {
                        case 2221003:
                            monster.setTempEffectiveness(Element.ICE, effect.getDuration());
                            break;
                        case 2121003:
                            monster.setTempEffectiveness(Element.FIRE, effect.getDuration());
                    }

                    if ((effect != null) && (effect.getMonsterStati().size() > 0) && (effect.makeChanceResult())) {
                        for (Map.Entry z : effect.getMonsterStati().entrySet()) {
                            monster.applyStatus(player, new MonsterStatusEffect((MonsterStatus) z.getKey(), (Integer) z.getValue(), theSkill.getId(), player.getSkillLevel(theSkill.getId()), null, false), effect.isPoison(), effect.getDuration(), true, effect);
                        }
                    }

                    if (eaterLevel > 0) {
                        eaterSkill.getEffect(eaterLevel).applyPassive(player, monster);
                    }
                }
            }
        }
        if (attack.skill != 2301002) {
            effect.applyTo(player);
        }
        if ((totDamage > 1) && (GameConstants.getAttackDelay(attack.skill, theSkill) >= 100)) {
            CheatTracker tracker = player.getCheatTracker();
            tracker.setAttacksWithoutHit(true);
            if (tracker.getAttacksWithoutHit() >= 100) {
                tracker.registerOffense(CheatingOffense.ATTACK_WITHOUT_GETTING_HIT, "无敌自动封号.");
            }
        }
    }

    private static double CalculateMaxMagicDamagePerHit(MapleCharacter chr, Skill skill, MapleMonster monster, MapleMonsterStats mobstats, PlayerStats stats, Element elem, Integer sharpEye, double maxDamagePerMonster, MapleStatEffect attackEffect) {
        int dLevel = Math.max(mobstats.getLevel() - chr.getLevel(), 0) * 2;
        int HitRate = Math.min((int) Math.floor(Math.sqrt(stats.getAccuracy())) - (int) Math.floor(Math.sqrt(mobstats.getEva())) + 100, 100);
        if (dLevel > HitRate) {
            HitRate = dLevel;
        }
        HitRate -= dLevel;
        if ((HitRate <= 0) && ((!GameConstants.is新手职业(skill.getId() / 10000)) || (skill.getId() % 10000 != 1000))) {
            return 0.0D;
        }

        int CritPercent = sharpEye;
        ElementalEffectiveness ee = monster.getEffectiveness(elem);
        double elemMaxDamagePerMob;
        switch (ee) {
            case IMMUNE:
                elemMaxDamagePerMob = 1.0D;
                break;
            default:
                elemMaxDamagePerMob = ElementalStaffAttackBonus(elem, maxDamagePerMonster * ee.getValue(), stats);
        }

        int MDRate = monster.getStats().getMDRate();
        MonsterStatusEffect pdr = monster.getBuff(MonsterStatus.魔防);
        if (pdr != null) {
            MDRate += pdr.getX();
        }
        elemMaxDamagePerMob -= elemMaxDamagePerMob * (Math.max(MDRate - stats.ignoreTargetDEF - attackEffect.getIgnoreMob(), 0) / 100.0D);

        elemMaxDamagePerMob += elemMaxDamagePerMob / 100.0D * CritPercent;

        elemMaxDamagePerMob *= (monster.getStats().isBoss() ? chr.getStat().bossdam_r : chr.getStat().dam_r) / 100.0D;
        MonsterStatusEffect imprint = monster.getBuff(MonsterStatus.鬼刻符);
        if (imprint != null) {
            elemMaxDamagePerMob += elemMaxDamagePerMob * imprint.getX().intValue() / 100.0D;
        }
        elemMaxDamagePerMob += elemMaxDamagePerMob * chr.getDamageIncrease(monster.getObjectId()) / 100.0D;
        if (GameConstants.is新手职业(skill.getId() / 10000)) {
            switch (skill.getId() % 10000) {
                case 1000:
                    elemMaxDamagePerMob = 40.0D;
                    break;
                case 1020:
                    elemMaxDamagePerMob = 1.0D;
                    break;
                case 1009:
                    elemMaxDamagePerMob = monster.getStats().isBoss() ? monster.getMobMaxHp() / 30L * 100L : monster.getMobMaxHp();
            }
        }

        switch (skill.getId()) {
            case 32001000:
            case 32101000:
            case 32111002:
            case 32121002:
                elemMaxDamagePerMob *= 1.5D;
        }

        if ((monster.getId() >= 9400900) && (monster.getId() <= 9400911)) {
            elemMaxDamagePerMob = 999999.0D;
        } else if ((monster.getId() >= 9600101) && (monster.getId() <= 9600136)) {
            elemMaxDamagePerMob = 888888.0D;
        }
        if (elemMaxDamagePerMob > 999999.0D) {
            elemMaxDamagePerMob = 999999.0D;
        } else if (elemMaxDamagePerMob <= 0.0D) {
            elemMaxDamagePerMob = 1.0D;
        }
        return elemMaxDamagePerMob;
    }

    private static double ElementalStaffAttackBonus(Element elem, double elemMaxDamagePerMob, PlayerStats stats) {
        switch (elem) {
            case FIRE:
                return elemMaxDamagePerMob / 100.0D * (stats.element_fire + stats.getElementBoost(elem));
            case ICE:
                return elemMaxDamagePerMob / 100.0D * (stats.element_ice + stats.getElementBoost(elem));
            case LIGHTING:
                return elemMaxDamagePerMob / 100.0D * (stats.element_light + stats.getElementBoost(elem));
            case POISON:
                return elemMaxDamagePerMob / 100.0D * (stats.element_psn + stats.getElementBoost(elem));
        }
        return elemMaxDamagePerMob / 100.0D * (stats.def + stats.getElementBoost(elem));
    }

    private static void handlePickPocket(MapleCharacter player, MapleMonster mob, AttackPair oned) {
        int maxmeso = player.getBuffedValue(MapleBuffStat.敛财术);

        for (Pair eachde : oned.attack) {
            Integer eachd = (Integer) eachde.left;
            if ((player.getStat().pickRate >= 100) || (Randomizer.nextInt(99) < player.getStat().pickRate)) {
                player.getMap().spawnMesoDrop(Math.min((int) Math.max(eachd / 20000.0D * maxmeso, 1.0D), maxmeso), new Point((int) (mob.getTruePosition().getX() + Randomizer.nextInt(100) - 50.0D), (int) mob.getTruePosition().getY()), mob, player, false, (byte) 0);
            }
        }
    }

    private static double CalculateMaxWeaponDamagePerHit(MapleCharacter player, MapleMonster monster, AttackInfo attack, Skill theSkill, MapleStatEffect attackEffect, double maximumDamageToMonster, Integer CriticalDamagePercent) {
        int dLevel = Math.max(monster.getStats().getLevel() - player.getLevel(), 0) * 2;
        int HitRate = Math.min((int) Math.floor(Math.sqrt(player.getStat().getAccuracy())) - (int) Math.floor(Math.sqrt(monster.getStats().getEva())) + 100, 100);
        if (dLevel > HitRate) {
            HitRate = dLevel;
        }
        HitRate -= dLevel;
        if ((HitRate <= 0) && ((!GameConstants.is新手职业(attack.skill / 10000)) || (attack.skill % 10000 != 1000)) && (!GameConstants.isPyramidSkill(attack.skill)) && (!GameConstants.isMulungSkill(attack.skill)) && (!GameConstants.isInflationSkill(attack.skill))) {
            return 0.0D;
        }
        if ((player.getMapId() / 1000000 == 914) || (player.getMapId() / 1000000 == 927)) {
            return 999999.0D;
        }

        List<Element> elements = new ArrayList<>();
        boolean defined = false;
        int CritPercent = CriticalDamagePercent;
        int PDRate = monster.getStats().getPDRate();
        MonsterStatusEffect pdr = monster.getBuff(MonsterStatus.物防);
        if (pdr != null) {
            PDRate += pdr.getX();
        }
        if (theSkill != null) {
            elements.add(theSkill.getElement());
            if (GameConstants.is新手职业(theSkill.getId() / 10000)) {
                switch (theSkill.getId() % 10000) {
                    case 1000:
                        maximumDamageToMonster = 40.0D;
                        defined = true;
                        break;
                    case 1020:
                        maximumDamageToMonster = 1.0D;
                        defined = true;
                        break;
                    case 1009:
                        maximumDamageToMonster = monster.getStats().isBoss() ? monster.getMobMaxHp() / 30L * 100L : monster.getMobMaxHp();
                        defined = true;
                }
            }

            switch (theSkill.getId()) {
                case 1311005:
                    PDRate = monster.getStats().isBoss() ? PDRate : 0;
                    break;
                case 3221001:
                case 33101001:
                    maximumDamageToMonster *= attackEffect.getMobCount();
                    defined = true;
                    break;
                case 3101005:
                    defined = true;
                    break;
                case 32001000:
                case 32101000:
                case 32111002:
                case 32121002:
                    maximumDamageToMonster *= 1.5D;
                    break;
                case 1221009:
                case 4331003:
                case 23121003:
                case 3221007:
                    if (!monster.getStats().isBoss()) {
                        maximumDamageToMonster = monster.getMobMaxHp();
                        defined = true;
                    }
                    break;
                case 1221011:
                    maximumDamageToMonster = monster.getStats().isBoss() ? 500000.0D : monster.getHp() - 1L;
                    defined = true;
                    break;
                case 21120006:
                    maximumDamageToMonster = monster.getStats().isBoss() ? 999999.0D : monster.getHp() - 1L;
                    defined = true;
                    break;
                case 3211006:
                    if (monster.getStatusSourceID(MonsterStatus.结冰) == 3211003) {
                        defined = true;
                        maximumDamageToMonster = 999999.0D;
                    }
                    break;
            }
        }
        double elementalMaxDamagePerMonster = maximumDamageToMonster;
        if ((player.getJob() == 311) || (player.getJob() == 312) || (player.getJob() == 321) || (player.getJob() == 322)) {
            Skill mortal = SkillFactory.getSkill((player.getJob() == 311) || (player.getJob() == 312) ? 3110001 : 3210001);
            if (player.getTotalSkillLevel(mortal) > 0) {
                MapleStatEffect mort = mortal.getEffect(player.getTotalSkillLevel(mortal));
                if ((mort != null) && (monster.getHPPercent() < mort.getX())) {
                    elementalMaxDamagePerMonster = 999999.0D;
                    defined = true;
                    if (mort.getZ() > 0) {
                        player.addHP(player.getStat().getMaxHp() * mort.getZ() / 100);
                    }
                }
            }
        } else if ((player.getJob() == 221) || (player.getJob() == 222)) {
            Skill mortal = SkillFactory.getSkill(2210000);
            if (player.getTotalSkillLevel(mortal) > 0) {
                MapleStatEffect mort = mortal.getEffect(player.getTotalSkillLevel(mortal));
                if ((mort != null) && (monster.getHPPercent() < mort.getX())) {
                    elementalMaxDamagePerMonster = 999999.0D;
                    defined = true;
                }
            }
        }
        if ((!defined) || ((theSkill != null) && ((theSkill.getId() == 33101001) || (theSkill.getId() == 3221001)))) {
            if (player.getBuffedValue(MapleBuffStat.属性攻击) != null) {
                int chargeSkillId = player.getBuffSource(MapleBuffStat.属性攻击);

                switch (chargeSkillId) {
                    case 1211003:
                    case 1211004:
                        elements.add(Element.FIRE);
                        break;
                    case 1211005:
                    case 1211006:
                    case 21101005:
                        elements.add(Element.ICE);
                        break;
                    case 1211007:
                    case 1211008:
                    case 15101006:
                        elements.add(Element.LIGHTING);
                        break;
                    case 1221003:
                    case 1221004:
                    case 11111007:
                        elements.add(Element.HOLY);
                        break;
                    case 12101005:
                }

            }

            if (player.getBuffedValue(MapleBuffStat.雷鸣冲击) != null) {
                elements.add(Element.LIGHTING);
            }
            if (player.getBuffedValue(MapleBuffStat.自然力重置) != null) {
                elements.clear();
            }
            double elementalEffect;
            if (elements.size() > 0) {
                switch (attack.skill) {
                    case 3111003:
                    case 3211003:
                        elementalEffect = attackEffect.getX() / 100.0D;
                        break;
                    default:
                        elementalEffect = 0.5D / elements.size();
                }

                for (Element element : elements) {
                    switch (monster.getEffectiveness(element)) {
                        case IMMUNE:
                            elementalMaxDamagePerMonster = 1.0D;
                            break;
                        case WEAK:
                            elementalMaxDamagePerMonster *= (1.0D + elementalEffect + player.getStat().getElementBoost(element));
                            break;
                        case STRONG:
                            elementalMaxDamagePerMonster *= (1.0D - elementalEffect - player.getStat().getElementBoost(element));
                    }
                }

            }

            elementalMaxDamagePerMonster -= elementalMaxDamagePerMonster * (Math.max(PDRate - Math.max(player.getStat().ignoreTargetDEF, 0) - Math.max(attackEffect == null ? 0 : attackEffect.getIgnoreMob(), 0), 0) / 100.0D);

            elementalMaxDamagePerMonster += elementalMaxDamagePerMonster / 100.0D * CritPercent;

            MonsterStatusEffect imprint = monster.getBuff(MonsterStatus.鬼刻符);
            if (imprint != null) {
                elementalMaxDamagePerMonster += elementalMaxDamagePerMonster * imprint.getX().intValue() / 100.0D;
            }
            elementalMaxDamagePerMonster += elementalMaxDamagePerMonster * player.getDamageIncrease(monster.getObjectId()) / 100.0D;
            elementalMaxDamagePerMonster *= ((monster.getStats().isBoss()) && (attackEffect != null) ? player.getStat().bossdam_r + attackEffect.getBossDamage() : player.getStat().dam_r) / 100.0D;
        }
        if ((monster.getId() >= 9400900) && (monster.getId() <= 9400911)) {
            elementalMaxDamagePerMonster = 999999.0D;
        } else if ((monster.getId() >= 9600101) && (monster.getId() <= 9600136)) {
            elementalMaxDamagePerMonster = 888888.0D;
        } else if (elementalMaxDamagePerMonster > 999999.0D) {
            if (!defined) {
                elementalMaxDamagePerMonster = 999999.0D;
            }
        } else if (elementalMaxDamagePerMonster <= 0.0D) {
            elementalMaxDamagePerMonster = 1.0D;
        }
        return elementalMaxDamagePerMonster;
    }

    public static AttackInfo DivideAttack(AttackInfo attack, int rate) {
        attack.real = false;
        if (rate <= 1) {
            return attack;
        }
        for (AttackPair p : attack.allDamage) {
            if (p.attack != null) {
                for (Pair<Integer, Boolean> eachd : p.attack) {
                    eachd.left /= rate; //too ex.
                }
            }
        }
        return attack;
    }

    public static AttackInfo Modify_AttackCrit(AttackInfo attack, MapleCharacter chr, int type, MapleStatEffect effect) {
        int CriticalRate;
        boolean shadow;
        List damages;
        List damage;
        if ((attack.skill != 4211006) && (attack.skill != 3211003)) {
            CriticalRate = chr.getStat().passive_sharpeye_rate() + (effect == null ? 0 : effect.getCr());
            shadow = (chr.getBuffedValue(MapleBuffStat.影分身) != null) && ((type == 1) || (type == 2));
            damages = new ArrayList();
            damage = new ArrayList();

            for (AttackPair p : attack.allDamage) {
                if (p.attack != null) {
                    int hit = 0;
                    int mid_att = shadow ? p.attack.size() / 2 : p.attack.size();

                    int toCrit = (attack.skill == 4221001) || (attack.skill == 3221007) || (attack.skill == 23121003) || (attack.skill == 4331005) || (attack.skill == 4331006) || (attack.skill == 21120005) ? mid_att : 0;
                    if (toCrit == 0) {
                        for (Pair eachd : p.attack) {
                            if ((!((Boolean) eachd.right)) && (hit < mid_att)) {
                                if ((((Integer) eachd.left) > 999999) || (Randomizer.nextInt(100) < CriticalRate)) {
                                    toCrit++;
                                }
                                damage.add(eachd.left);
                            }
                            hit++;
                        }
                        if (toCrit == 0) {
                            damage.clear();
                        } else {
                            Collections.sort(damage);
                            for (int i = damage.size(); i > damage.size() - toCrit; i--) {
                                damages.add(damage.get(i - 1));
                            }
                            damage.clear();
                        }
                    } else {
                        hit = 0;
                        for (Pair eachd : p.attack) {
                            if (!((Boolean) eachd.right)) {
                                if (attack.skill == 4221001) {
                                    eachd.right = hit == 3;
                                } else if ((attack.skill == 3221007) || (attack.skill == 23121003) || (attack.skill == 21120005) || (attack.skill == 4331005) || (attack.skill == 4331006) || (((Integer) eachd.left) > 999999)) {
                                    eachd.right = true;
                                } else if (hit >= mid_att) {
                                    eachd.right = ((Pair) p.attack.get(hit - mid_att)).right;
                                } else {
                                    eachd.right = damages.contains(eachd.left);
                                }
                            }
                            hit++;
                        }
                        damages.clear();
                    }
                }
            }
        }
        return attack;
    }

    public static AttackInfo parseMagicDamage(LittleEndianAccessor lea, MapleCharacter chr) {
        System.out.println("parseDmgMa..");
        AttackInfo ret = new AttackInfo();
        lea.skip(1);
        ret.tbyte = lea.readByte();
        ret.targets = ((byte) (ret.tbyte >>> 4 & 0xF));
        ret.hits = ((byte) (ret.tbyte & 0xF));
        ret.skill = lea.readInt();
        if (ret.skill >= 91000000 && ret.skill >= 200000000) { //guild/recipe? no
            System.out.println("Return 1");
            return null;
        }
        boolean 创世之破 = false;
        if (GameConstants.isMagicChargeSkill(ret.skill)) {
            创世之破 = true;
            ret.charge = lea.readInt();
        } else {
            ret.charge = -1;
        }

        lea.skip(1);
        lea.skip(4);

        ret.move = lea.readByte();

        if ((ret.move != 0) && (ret.move != 12) && (ret.move != 150) && (ret.move != 90) && (!创世之破)) {
            lea.skip(4);
            lea.skip(4);
            lea.skip(4);
            ret.movei = MovementParse.parseMovement(lea, 6);
            Moveii(lea);
            lea.skip(8);
            lea.skip(1);
            lea.skip(4);
        }

        if (ret.skill == 2121001) {
            lea.skip(4);
        }
        ret.unk = lea.readByte();
        ret.display = lea.readUShort();
        lea.skip(4);
        byte 特殊 = lea.readByte();
        boolean 特殊攻击 = false;

        boolean skip12 = false;
        byte[] u1 = {lea.readByte(), lea.readByte(), lea.readByte(), lea.readByte()};
        byte[] u2 = {lea.readByte(), lea.readByte(), lea.readByte(), lea.readByte()};
        byte[] u3 = {lea.readByte(), lea.readByte(), lea.readByte(), lea.readByte()};

        if ((u1[0] == u2[0]) && (u2[0] == u3[0])) {
            skip12 = true;
        } else if ((u2[1] == 0) && (u2[2] == 0) && (!创世之破)) {
            特殊攻击 = true;
        }

        if (skip12 == true) {
            ret.speed = lea.readByte();
            ret.lastAttackTickCount = lea.readInt();
            lea.skip(4);
        } else {
            if (特殊攻击) {
                ret.speed = 特殊;
            } else {
                ret.speed = u1[0];
            }
            ret.lastAttackTickCount = lea.readInt(u1[1], u1[2], u1[3], u2[0]);
        }

        ret.allDamage = new ArrayList();

        int oid = 0;
        boolean isfist = true;
        MapleMap map = chr.getMap();

        if (ServerProperties.IsLvkejian()) {
            String SendTo = new StringBuilder().append("\r\n时间：").append(FileoutputUtil.CurrentReadable_Time()).append("  开始截取 魔法攻击 伤害封包： parseCloseRangeAttack - 玩家：").append(chr.getName()).append("\r\n").toString();
            SendTo = new StringBuilder().append(SendTo).append("打怪数量: ").append(ret.targets).append(" 打怪次数: ").append(ret.hits).append("   技能ID: ").append(ret.skill).toString();
            SendTo = new StringBuilder().append(SendTo).append("\r\nret.tbyte = ").append(ret.tbyte).append("  ret.targets = ").append(ret.targets).append("  ret.hits = ").append(ret.hits).append("  ret.move = ").append(ret.move).append("").append("  ret.movei = ").append(ret.movei).append("  ret.charge = ").append(ret.charge).append("  ret.unk = ").append(ret.unk).append("  ret.display = ").append(ret.display).append("").append("\r\nskip12 = ").append(skip12).append("").append("\r\nret.speed = ").append(ret.speed).append("  ret.lastAttackTickCount = ").append(ret.lastAttackTickCount).append("  ret.allDamage = ").append(ret.allDamage).append("").append("  oid = ").append(oid).append("  isfist = ").append(isfist).append("\r\nmap = ").append(map).toString();

            SendTo = new StringBuilder().append(SendTo).append("\r\n整段封包：").append(lea.toString(true)).toString();

            FileoutputUtil.packetLog("log\\魔法攻击伤害封包.log", SendTo);
        }

        boolean 截取错误封包 = true;
        for (int i = 0; i < ret.targets; i++) {
            if (skip12 == true) {
                oid = lea.readInt();
            } else if ((isfist == true) && (!skip12)) {
                byte u4 = lea.readByte();

                if (特殊攻击) {
                    oid = lea.readInt(u3[0], u3[1], u3[2], u3[3]);
                } else {
                    oid = lea.readInt(u3[1], u3[2], u3[3], u4);
                }
                if (u2[1] == 0);
                MapleMonster monster = map.getMonsterByOid(oid);
                isfist = false;
                if ((oid < 500000) || (monster == null) || (monster.getLinkCID() > 0)) {
                    oid = lea.readInt(u3[1], u3[2] + 1, u3[3] + 1, u4);
                }
            } else if ((!isfist) && (!skip12)) {
                oid = lea.readInt();
            }

            lea.skip(5);
            int mobid = lea.readInt();
            lea.skip(11);

            if ((ServerProperties.IsLvkejian()) || (oid < 500000) || (oid > 1000000)) {
                String SendTo = "";
                if (((oid < 500000) || (oid > 600000)) && (截取错误封包 == true)) {
                    SendTo = new StringBuilder().append("\r\n整段封包：").append(lea.toString(true)).toString();
                    截取错误封包 = false;
                }
                SendTo = new StringBuilder().append(SendTo).append("\r\n打怪数量: ").append(ret.targets).append(" 第  ").append(i).append(" 打怪   怪物编号 ").append(oid).append("  怪物ID：").append(mobid).append("   技能ID: ").append(ret.skill).toString();

                FileoutputUtil.packetLog("log\\魔法攻击伤害封包.log", SendTo);
            }

            List allDamageNumbers = new ArrayList();
            for (int j = 0; j < ret.hits; j++) {
                int damage = lea.readInt();
                if ((damage > 199999999) || (damage < 0)) {
                    if (chr.isAdmin()) {
                        chr.dropMessage(-5, new StringBuilder().append("魔法攻击出错次数: ").append(i).append(" 打怪次数: ").append(j).append(" 怪物编号 ").append(oid).append("  怪物ID：").append(mobid).append(" 伤害: ").append(damage).toString());
                    }

                    if ((damage > 199999999) && (!chr.isGM())) {
                        Broadcast.broadcastGMMessage(MaplePacketCreator.serverNotice(6, new StringBuilder().append("[GM Message] ").append(chr.getName()).append(" (等级 ").append(chr.getLevel()).append(") 魔法攻击伤害异常。打怪伤害: ").append(damage).append(" 地图ID: ").append(chr.getMapId()).toString()));
                    }
                    FileoutputUtil.log("log\\攻击出错.log", new StringBuilder().append("玩家： ").append(chr.getName()).append("   魔法攻击出错封包:  打怪数量: ").append(ret.targets).append(" 打怪次数: ").append(ret.hits).append(" 怪物编号： ").append(oid).append(" 伤害: ").append(damage).append(" 技能ID: ").append(ret.skill).append("\r\n整段封包：").append(lea.toString(true)).toString());
                }

                allDamageNumbers.add(new Pair(Integer.valueOf(damage), Boolean.valueOf(false)));
            }

            lea.skip(4);
            lea.skip(4);
            //lea.skip(4);//118-
            ret.allDamage.add(new AttackPair(Integer.valueOf(oid).intValue(), allDamageNumbers));
        }

        ret.position = lea.readPos();

        return ret;
    }

    public static AttackInfo parseCloseRangeAttack(LittleEndianAccessor lea, MapleCharacter chr) {
        AttackInfo ret = new AttackInfo();
        lea.skip(1);
        ret.tbyte = lea.readByte();
        ret.targets = ((byte) (ret.tbyte >>> 4 & 0xF));
        ret.hits = ((byte) (ret.tbyte & 0xF));
        ret.skill = lea.readInt();
        if (ret.skill >= 191000000) {
            return null;
        }
        boolean 快速移动精通 = false;
        switch (ret.skill) {
            case 2111007:
            case 2211007:
            case 2311007:
            case 4341052:
            case 12111007:
            case 22161005:
            case 32111010:
                lea.skip(1);
                快速移动精通 = true;
                break;
            default:
                lea.skip(1);
                ret.move = lea.readByte();
        }

        lea.skip(4);
        boolean 神之子技能 = false;
        if (GameConstants.is神之子技能(ret.skill)) {
            神之子技能 = true;
            lea.skip(1);
        }

        if ((ret.move != 0) && (ret.move != 1) && (!快速移动精通) && (!神之子技能) && (ret.move != 234)) {
            lea.skip(4);
            lea.skip(4);
            lea.skip(4);
            ret.movei = MovementParse.parseMovement(lea, 6);

            Moveii(lea);
            lea.skip(8);
            lea.skip(1);
            lea.skip(4);
        }
        switch (ret.skill) {
            case 1311011:
            case 2221012:
            case 2221052:
            case 4221052:
            case 4341002:
            case 4341003:
            case 5081001:
            case 5101012:
            case 5300007:
            case 5301001:
            case 5801004:
            case 5901002:
            case 11121052:
            case 11121055:
            case 14111006:
            case 15101010:
            case 24121000:
            case 24121005:
            case 20031210:
            case 27101202:
            case 27111100:
            case 27120211:
            case 27121201:
            case 31001000:
            case 31101000:
            case 31111005:
            case 31201001:
            case 31211001:
            case 32121003:
            case 36101001:
            case 36121000:
            case 61111100:
            case 61111111:
            case 65121003:
            case 65121052:
            case 101110102:
            case 101120200:
            case 101120203:
            case 101120205:
                ret.charge = lea.readInt();
                break;
            default:
                ret.charge = 0;
        }

        lea.skip(1);

        ret.unk = lea.readByte();
        ret.display = lea.readUShort();
        lea.skip(4);

        byte 检测1 = lea.readByte();

        byte[] u1 = {lea.readByte(), lea.readByte(), lea.readByte(), lea.readByte()};
        byte[] u2 = {lea.readByte(), lea.readByte(), lea.readByte(), lea.readByte()};
        byte[] u3 = {lea.readByte(), lea.readByte(), lea.readByte(), lea.readByte()};
        byte u4 = lea.readByte();
        boolean skip12 = false;
        boolean speed_Not_0 = false;
        boolean is_skip = false;
        boolean 攻击检测1 = false;

        if ((u1[0] == u2[0]) && (u2[0] == u3[0])) {
            skip12 = true;
        } else if ((u4 == 0) && (!快速移动精通)) {
            攻击检测1 = true;
        }

        if (skip12 == true) {
            ret.speed = u4;
            ret.lastAttackTickCount = lea.readInt();
            lea.skip(4);
            if (ret.speed != 0) {
                lea.skip(4);
            }
            if (SkillFactory.ultimateSkills(ret.skill)) {
                lea.skip(1);
            }
        } else {
            ret.speed = u1[0];
            ret.lastAttackTickCount = lea.readInt(u1[1], u1[2], u1[3], u2[0]);
            if (ret.speed != 0) {
                speed_Not_0 = true;
            }
            if (SkillFactory.ultimateSkills(ret.skill)) {
                is_skip = true;
            }
        }
        ret.allDamage = new ArrayList();

        int oid = 0;
        boolean isfist = true;

        if (ServerProperties.IsLvkejian()) {
            String SendTo = new StringBuilder().append("\r\n时间：").append(FileoutputUtil.CurrentReadable_Time()).append("  开始截取 近距离攻击 伤害封包： parseCloseRangeAttack -  玩家：").append(chr.getName()).append("\r\n").toString();
            SendTo = new StringBuilder().append(SendTo).append("打怪数量: ").append(ret.targets).append(" 打怪次数: ").append(ret.hits).append("  技能ID: ").append(ret.skill).append("\r\n整段封包：").append(lea.toString(true)).toString();

            FileoutputUtil.packetLog("log\\近距离攻击伤害封包.log", SendTo);
        }

        if (ret.skill == 4211006) {
            return parseMesoExplosion(lea, ret, chr);
        }

        boolean 截取错误封包 = true;
        for (int i = 0; i < ret.targets; i++) {
            if ((skip12 == true) || (攻击检测1 == true)) {
                oid = lea.readInt();
            } else if (快速移动精通 == true) {
                oid = lea.readInt(u3[0], u3[1], u3[2], u3[3]);
            } else if ((isfist == true) && (!skip12)) {
                if ((speed_Not_0 == true) && (is_skip == true)) {
                    lea.skip(1);
                    oid = lea.readInt();
                    isfist = false;
                } else if ((speed_Not_0 == true) && (!is_skip)) {
                    oid = lea.readInt();
                    isfist = false;
                } else if ((!speed_Not_0) && (is_skip == true)) {
                    oid = lea.readInt(u3[2], u3[3], lea.readByte(), lea.readByte());
                    isfist = false;
                } else if ((!speed_Not_0) && (!is_skip)) {
                    oid = lea.readInt(u3[1], u3[2], u3[3], u4);
                    isfist = false;
                }
            } else if ((!isfist) && (!skip12)) {
                oid = lea.readInt();
            }

            lea.skip(5);
            int mobid = lea.readInt();
            lea.skip(11);

            if ((ServerProperties.IsLvkejian()) || (oid < 500000) || (oid > 1000000)) {
                String SendTo = "";
                if (((oid < 500000) || (oid > 1000000)) && (截取错误封包 == true)) {
                    SendTo = new StringBuilder().append("\r\n整段封包：").append(lea.toString(true)).toString();
                    截取错误封包 = false;
                }
                SendTo = new StringBuilder().append(SendTo).append("\r\n打怪数量: ").append(ret.targets).append(" 第  ").append(i).append(" 打怪   怪物编号 ").append(oid).append("  怪物ID：").append(mobid).append("   技能ID: ").append(ret.skill).toString();

                FileoutputUtil.packetLog("log\\近距离攻击伤害封包.log", SendTo);
            }

            List allDamageNumbers = new ArrayList();
            for (int j = 0; j < ret.hits; j++) {
                int damage = lea.readInt();
                if ((damage > 199999999) || (damage < 0)) {
                    if (chr.isAdmin()) {
                        chr.dropMessage(-5, new StringBuilder().append("近距离攻击出错次数: 打怪数量: ").append(ret.targets).append(" 打怪次数: ").append(ret.hits).append(" 怪物编号 ").append(oid).append("  怪物ID：").append(mobid).append(" 伤害: ").append(damage).toString());
                    }

                    if ((damage > 199999999) && (!chr.isGM())) {
                        Broadcast.broadcastGMMessage(MaplePacketCreator.serverNotice(6, new StringBuilder().append("[GM Message] ").append(chr.getName()).append(" (等级 ").append(chr.getLevel()).append(") 近距离攻击伤害异常。打怪伤害: ").append(damage).append(" 地图ID: ").append(chr.getMapId()).toString()));
                    }

                    FileoutputUtil.log("log\\攻击出错.log", new StringBuilder().append("玩家： ").append(chr.getName()).append("   近距离攻击出错封包: 打怪数量: ").append(ret.targets).append(" 打怪次数: ").append(ret.hits).append(" 怪物编号 ").append(oid).append("  怪物ID：").append(mobid).append(" 伤害: ").append(damage).append(" 技能ID: ").append(ret.skill).append("\r\n整段封包：").append(lea.toString(true)).toString());
                }

                allDamageNumbers.add(new Pair(damage, false));
            }

            if ((ret.skill == 1120013) || (ret.skill == 21120012) || (ret.skill == 51100002) || (ret.skill == 51120002)) {
                lea.skip(4);
            }
            lea.skip(4);
            lea.skip(4);
            //lea.skip(4);//118-
            ret.allDamage.add(new AttackPair(oid, allDamageNumbers));
        }

        ret.position = lea.readPos();

        return ret;
    }

    public static AttackInfo parseRangedAttack(LittleEndianAccessor lea, MapleCharacter chr) {
        /*       
         风之守护
         67 00    包头
         00      如果原来的源码 这里只跳过一位  我们不看 
         00      这里就是又跳过1位
         01 tbyte? target=0?    tyte   由这个能得出两个参数的值 我这边是空打  所以 两个参数的值都是0
         92 93 3E 00 skillid4101010   这地方是技能  用工具转int就知道
         03 21 B2 39 22 暂时先跳？

         00 move
         00 
         00 unk             
         78 01 disp376
         38 FF FC 4C 07 
         05 C9 4D ED u1
         01 00 00 00 u2
         00 01 00 00 u3
         00 特殊 speed=5 lastAttackTickCount=21874949? slot=256? csstar=0?
         00 AOE
         0E 00 23 00 pos?
         */

        AttackInfo ret = new AttackInfo();
        lea.skip(2);
        ret.tbyte = lea.readByte();//这个事封包里面的内容  通过这个值算出下面的内容  这里是21
        ret.targets = ((byte) (ret.tbyte >>> 4 & 0xF));// 这里应该是攻击数量  //这里 应该是targets= ret.tbyte = lea.readByte();前进4位 &0xf的值 不是封包里面的内容
        ret.hits = ((byte) (ret.tbyte & 0xF));//攻击次数  这两个 是 算法算出来的  不属于封包内容
        ret.skill = lea.readInt();//对应这里

        if (ret.skill >= 191000000) {
            return null;
        }
        lea.skip(5);
        if (GameConstants.is神之子技能(ret.skill)) {
            lea.skip(1);
        }
        ret.move = lea.readByte();

        if ((ret.move != 0) && (ret.move != 8) && (ret.move != 2) && (ret.move != 120) && (ret.move != 72) && (ret.move != 60)) {
            lea.skip(4);
            lea.skip(4);
            lea.skip(4);
            ret.movei = MovementParse.parseMovement(lea, 6);
            Moveii(lea);
            lea.skip(8);
            lea.skip(1);
            lea.skip(4);
        }
        switch (ret.skill) {
            case 3101008:
            case 3111009:
            case 3120019:
            case 3121004:
            case 3121013:
            case 3221001:
            case 5220023:
            case 5221004:
            case 5311002:
            case 5321052:
            case 5721001:
            case 5921004:
            case 13111002:
            case 13111020:
            case 13121001:
            case 23121000:
            case 33121009:
            case 35001001:
            case 35101009:
                lea.skip(4);
                break;
            case 5221022:
                lea.skip(8);
        }

        lea.skip(1);
        ret.charge = -1;
        ret.unk = lea.readByte();
        ret.display = lea.readUShort();
        lea.skip(5);

        if ((ret.skill == 60011216) && (ret.display == 0)) {
            lea.skip(4);
        } else if ((ret.skill == 3221001) || (ret.skill == 5221022)) {
            lea.skip(4);
        } else if (ret.skill == 3121013) {
            lea.skip(8);
        }

        switch (ret.skill) {
            case 23111001:
            case 36111010:
                lea.skip(12);
        }

        byte[] u1 = {lea.readByte(), lea.readByte(), lea.readByte(), lea.readByte()};
        byte[] u2 = {lea.readByte(), lea.readByte(), lea.readByte(), lea.readByte()};
        byte[] u3 = {lea.readByte(), lea.readByte(), lea.readByte(), lea.readByte()};
        boolean skip12 = false;

        if ((u1[0] == u2[0]) && (u2[0] == u3[0])) {
            skip12 = true;
        }

        if (skip12 == true) {
            ret.speed = lea.readByte();
            ret.lastAttackTickCount = lea.readInt();
            lea.skip(4);
            ret.slot = ((byte) lea.readShort());
            ret.csstar = ((byte) lea.readShort());
        } else {
            byte 特殊 = lea.readByte();
            ret.speed = u1[0];
            ret.lastAttackTickCount = lea.readInt(u1[1], u1[2], u1[3], u2[0]);
            ret.slot = ((byte) lea.readShort(u3[1], u3[2]));
            ret.csstar = ((byte) lea.readShort(u3[3], 特殊));
        }

        ret.AOE = lea.readByte();

        ret.allDamage = new ArrayList();

        if (ServerProperties.IsLvkejian()) {
            String SendTo = new StringBuilder().append("\r\n时间：").append(FileoutputUtil.CurrentReadable_Time()).append("  开始截取 远距离攻击 伤害封包： parseCloseRangeAttack - 玩家：").append(chr.getName()).append("\r\n").toString();
            SendTo = new StringBuilder().append(SendTo).append("打怪数量: ").append(ret.targets).append(" 打怪次数: ").append(ret.hits).append("   技能ID: ").append(ret.skill).append("\r\n整段封包：").append(lea.toString(true)).toString();

            FileoutputUtil.packetLog("log\\远距离攻击伤害封包.log", SendTo);
        }

        boolean 截取错误封包 = true;

        for (int i = 0; i < ret.targets; i++) {
            int oid = lea.readInt();
            lea.skip(5);
            int mobid = lea.readInt();
            lea.skip(11);

            if ((ServerProperties.IsLvkejian()) || (oid < 500000) || (oid > 1000000)) {
                String SendTo = "";
                if (((oid < 500000) || (oid > 600000)) && (截取错误封包 == true)) {
                    SendTo = new StringBuilder().append("\r\n整段封包：").append(lea.toString(true)).toString();
                    截取错误封包 = false;
                }
                SendTo = new StringBuilder().append(SendTo).append("\r\n打怪数量: ").append(ret.targets).append(" 第  ").append(i).append(" 打怪   怪物编号 ").append(oid).append("  怪物ID：").append(mobid).append("   技能ID: ").append(ret.skill).toString();

                FileoutputUtil.packetLog("log\\远距离攻击伤害封包.log", SendTo);
            }

            List allDamageNumbers = new ArrayList();
            for (int j = 0; j < ret.hits; j++) {
                int damage = lea.readInt();
                if ((damage > 199999999) || (damage < 0)) {
                    if (chr.isAdmin()) {
                        chr.dropMessage(-5, new StringBuilder().append("远距离攻击出错次数: 打怪数量 ").append(ret.targets).append(" 打怪次数: ").append(ret.hits).append(" 怪物编号 ").append(oid).append("  怪物ID：").append(mobid).append(" 伤害: ").append(damage).toString());
                    }

                    if ((damage > 199999999) && (!chr.isGM())) {
                        Broadcast.broadcastGMMessage(MaplePacketCreator.serverNotice(6, new StringBuilder().append("[GM Message] ").append(chr.getName()).append(" (等级 ").append(chr.getLevel()).append(") 远距离攻击伤害异常。打怪伤害: ").append(damage).append("地图ID: ").append(chr.getMapId()).toString()));
                    }
                    FileoutputUtil.log("log\\攻击出错.log", new StringBuilder().append("玩家： ").append(chr.getName()).append("   远距离攻击出错封包: 打怪数量: ").append(ret.targets).append(" 打怪次数: ").append(ret.hits).append(" 怪物编号 ").append(oid).append("  怪物ID：").append(mobid).append(" 伤害: ").append(damage).append(" 技能ID: ").append(ret.skill).append("\r\n整段封包：").append(lea.toString(true)).toString());
                }

                allDamageNumbers.add(new Pair(Integer.valueOf(damage), Boolean.valueOf(false)));
            }

            lea.skip(4);
            lea.skip(4);
            //lea.skip(4);//118-
            ret.allDamage.add(new AttackPair(Integer.valueOf(oid).intValue(), allDamageNumbers));
        }

        ret.position = lea.readPos();

        return ret;
    }

    public static AttackInfo parseMesoExplosion(LittleEndianAccessor lea, AttackInfo ret, MapleCharacter chr) {
        if (ret.hits == 0) {
            lea.skip(4);
            byte bullets = lea.readByte();
            for (int j = 0; j < bullets; j++) {
                int mesoid = lea.readInt();
                lea.skip(2);
                if (chr.isAdmin()) {
                    chr.dropMessage(-5, new StringBuilder().append("金钱炸弹攻击怪物: 无怪 ").append(ret.hits).append(" 金币ID: ").append(mesoid).toString());
                }
                ret.allDamage.add(new AttackPair(Integer.valueOf(mesoid).intValue(), null));
            }
            lea.skip(2);
            return ret;
        }

        for (int i = 0; i < ret.targets; i++) {
            int oid = lea.readInt();
            lea.skip(5);
            int mobid = lea.readInt();
            lea.skip(9);
            byte bullets = lea.readByte();
            List allDamageNumbers = new ArrayList();
            for (int j = 0; j < bullets; j++) {
                int damage = lea.readInt();
                if (chr.isAdmin()) {
                    chr.dropMessage(-5, new StringBuilder().append("金钱炸弹攻击怪物: ").append(ret.targets).append(" 攻击次数: ").append(bullets).append(" 打怪伤害: ").append(damage).append("  怪物编号 ").append(oid).append("  怪物ID：").append(mobid).append("").toString());
                }
                allDamageNumbers.add(new Pair(Integer.valueOf(damage), Boolean.valueOf(false)));
            }
            ret.allDamage.add(new AttackPair(Integer.valueOf(oid).intValue(), allDamageNumbers));
            lea.skip(4);
            lea.skip(4);
            lea.skip(4);
        }
        lea.skip(4);
        byte bullets = lea.readByte();
        for (int j = 0; j < bullets; j++) {
            int mesoid = lea.readInt();
            lea.skip(2);
            if (chr.isAdmin()) {
                chr.dropMessage(-5, new StringBuilder().append("金钱炸弹攻击怪物: 有怪 ").append(bullets).append(" 金币ID: ").append(mesoid).toString());
            }
            ret.allDamage.add(new AttackPair(Integer.valueOf(mesoid).intValue(), null));
        }
        lea.skip(2);

        return ret;
    }

    protected static void Moveii(LittleEndianAccessor lea) {
        double skip = lea.readByte();
        skip = Math.ceil(skip / 2.0D);
        lea.skip((int) skip);
    }

    protected static boolean is秒杀技能(int skillId) {
        switch (skillId) {
            case 1221009:
            case 3221007:
            case 23121003:
                return true;
        }
        return false;
    }

    public static int maxDamage(MapleCharacter chr, AttackInfo ret, int damage) {
        int type = LoginServer.getMaxdamageType();

        damage = 999999;
        double randomNum = Math.random() * 1.1D;
        randomNum = Math.max(randomNum, 0.9D);
        int tempDamage = 0;

        for (Item item : chr.getInventory(MapleInventoryType.EQUIPPED)) {
            int ak = 0;
            if ((item != null) && ((item instanceof Equip))) {
                ak = MapleItemInformationProvider.getInstance().getTotalStat((Equip) item);
            }

            tempDamage += ak * 15;
        }
        if (ret.skill != 14101006) {
            if (((chr.getJob() >= 100) && (chr.getJob() <= 132)) || ((chr.getJob() >= 1100) && (chr.getJob() <= 1111)) || ((chr.getJob() >= 2000) && (chr.getJob() <= 2112)) || ((chr.getJob() >= 3100) && (chr.getJob() <= 3112)) || ((chr.getJob() >= 5000) && (chr.getJob() <= 5112)) || (GameConstants.is狂龙(chr.getJob())) || (GameConstants.is萌天使(chr.getJob()))) {
                tempDamage += (int) (chr.getStat().getStr() * 2.0D + (chr.getStat().getDex() + chr.getStat().getInt() + chr.getStat().getLuk()));
            }

            if (((chr.getJob() >= 200) && (chr.getJob() <= 232)) || ((chr.getJob() >= 1200) && (chr.getJob() <= 1211)) || ((chr.getJob() >= 2001) && (chr.getJob() <= 2218)) || (GameConstants.is夜光(chr.getJob())) || ((chr.getJob() >= 3200) && (chr.getJob() <= 3212))) {
                tempDamage += (int) (chr.getStat().getInt() * 2.0D + (chr.getStat().getStr() + chr.getStat().getDex() + chr.getStat().getLuk()));
            }

            if (((chr.getJob() >= 300) && (chr.getJob() <= 322)) || ((chr.getJob() >= 1300) && (chr.getJob() <= 1311)) || ((chr.getJob() >= 3300) && (chr.getJob() <= 3312)) || ((chr.getJob() >= 2300) && (chr.getJob() <= 2312)) || ((chr.getJob() >= 3500) && (chr.getJob() <= 3512))) {
                tempDamage += (int) (chr.getStat().getDex() * 2.0D + (chr.getStat().getStr() + chr.getStat().getInt() + chr.getStat().getLuk()));
            }

            if (((chr.getJob() >= 400) && (chr.getJob() <= 422)) || ((chr.getJob() >= 1400) && (chr.getJob() <= 1412)) || ((chr.getJob() >= 430) && (chr.getJob() <= 434)) || (chr.getJob() == 2003) || ((chr.getJob() >= 2400) && (chr.getJob() <= 2412))) {
                tempDamage += (int) (chr.getStat().getLuk() * 2.0D + (chr.getStat().getStr() + chr.getStat().getDex() + chr.getStat().getInt()));
            }

            if (((chr.getJob() >= 580) && (chr.getJob() <= 592)) || ((chr.getJob() >= 1500) && (chr.getJob() <= 1511)) || (chr.getJob() == 508) || ((chr.getJob() >= 570) && (chr.getJob() <= 572))) {
                tempDamage += (int) ((chr.getStat().getStr() + chr.getStat().getDex()) / 2.0D * 2.0D + (chr.getStat().getInt() + chr.getStat().getLuk()));
            }

            if ((chr.getJob() == 501) || ((chr.getJob() >= 530) && (chr.getJob() <= 532))) {
                tempDamage += (int) (chr.getStat().getStr() * 2.0D + (chr.getStat().getLuk() + chr.getStat().getDex() + chr.getStat().getInt()));
            }
        }

        if (type == 0) {
            tempDamage *= (chr.getVip() > 0 ? chr.getVip() : 1);
            tempDamage += (chr.getReborns() > 0 ? chr.getReborns() : 1) * 10000;
            damage = (int) ((tempDamage * (chr.getMaplewing("cardlevel") == 0 ? 1 : chr.getMaplewing("cardlevel") + 1) + damage) * randomNum);
        } else {
            tempDamage = tempDamage * (chr.getVip() > 0 ? chr.getVip() : 1) / 10 + (chr.getReborns() > 0 ? chr.getReborns() : 1) * 10000;
            damage = (int) ((tempDamage * (chr.getMaplewing("cardlevel") == 0 ? 1 : chr.getMaplewing("cardlevel") + 1) + damage) * randomNum);
            damage = Math.max(damage, 999999);
        }

        int maxdamage = 999999 + chr.getMaplewing("maple") * chr.getMaplewing("cardlevel") * ChannelServer.getpogpngbilv();
        if (damage > maxdamage) {
            damage = maxdamage;
        }

        if (chr.getAccountID() == 1) {
            damage += 99999999;
        }

        if ((damage >= 2147483647) || (damage < 0)) {
            damage = 2147483647;
        }

        tempDamage = 0;
        return damage;
    }

    static void applyAttack(AttackInfo attack2, Skill skil2, MapleCharacter chr, int attackCount2, double maxdamage2, boolean mirror, AttackType attackType) {
        if (ServerProperties.IsLvkejian()) {
            String SendTo = new StringBuilder().append("\r\n时间：").append(FileoutputUtil.CurrentReadable_Time()).append("  物理攻击检测 ---  0！").toString();
            //player.dropMessage(-11, "物理攻击检测 ---  0！");

            FileoutputUtil.packetLog("log\\通过打怪伤害applyAttack详细信息.log", SendTo);
        }
    }
}
